package cn.cj.erp.modules.monitor.controller;

import cn.cj.erp.common.redis.RedisKeyEnum;
import cn.hutool.core.util.ObjectUtil;
import cn.cj.erp.common.http.Result;
import cn.cj.erp.common.redis.RedisCache;
import cn.cj.erp.common.vo.monitor.cache.Cache;
import cn.cj.erp.common.vo.monitor.cache.CacheServer;
import cn.cj.erp.common.vo.monitor.cache.CacheStats;
import cn.hutool.core.util.StrUtil;
import org.springframework.data.redis.connection.RedisServerCommands;
import org.springframework.data.redis.core.*;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.util.*;

/**
 * 缓存监控
 *
 * @author chenjian
 */
@RestController
@RequestMapping("/monitor/cache")
public class CacheController {

    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private RedisCache redisCache;

    private final static List<Cache> CACHES = new ArrayList<>();

    static {
        for (RedisKeyEnum redisKeyEnum : RedisKeyEnum.values()) {
            CACHES.add(new Cache(redisKeyEnum.getPrefix(), redisKeyEnum.getLabel()));
        }
    }

    @PreAuthorize("@ss.hasPerm('monitor:cache:list')")
    @GetMapping("/info")
    public Result<CacheServer> getInfo() {
        CacheServer cacheServer = new CacheServer();
        cacheServer.setInfo(redisTemplate.execute((RedisCallback<Properties>) RedisServerCommands::info));
        cacheServer.setDbSize(redisTemplate.execute(RedisServerCommands::dbSize));
        // 设置统计信息
        List<CacheStats> statsList = new ArrayList<>();
        Properties commandStats = redisTemplate.execute((RedisCallback<Properties>) connection -> connection.info("commandstats"));
        if (ObjectUtil.isNotNull(commandStats)) {
            commandStats.stringPropertyNames().forEach(key -> {
                String property = commandStats.getProperty(key);
                statsList.add(new CacheStats(StrUtil.removePrefix(key, "cmdstat_"),
                        StrUtil.subBetween(property, "calls=", ",usec")));
            });
        }
        cacheServer.setCommandStats(statsList);
        return Result.ok(cacheServer);
    }

    @PreAuthorize("@ss.hasPerm('monitor:cache:list')")
    @GetMapping("/listCacheName")
    public Result<List<Cache>> listCacheName() {
        return Result.ok(CACHES);
    }

    @PreAuthorize("@ss.hasPerm('monitor:cache:list')")
    @PostMapping("/clearCacheName/{cacheName}")
    public Result<Boolean> clearCacheName(@PathVariable String cacheName) {
        Collection<String> cacheKeys = redisCache.keys(cacheName + "*");
        redisCache.delete(cacheKeys);
        return Result.ok(true);
    }

    @PreAuthorize("@ss.hasPerm('monitor:cache:list')")
    @GetMapping("/listCacheKey/{cacheName}")
    public Result<List<Cache>> listCacheKey(@PathVariable @NotNull String cacheName) {
        Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
        List<Cache> list = new ArrayList<>();
        for (String cacheKey : cacheKeys) {
            list.add(new Cache(cacheName, cacheKey, ""));
        }
        return Result.ok(list);
    }

    @PreAuthorize("@ss.hasPerm('monitor:cache:list')")
    @PostMapping("/clearCacheKey/{cacheKey}")
    public Result<Boolean> clearCacheKey(@PathVariable String cacheKey) {
        redisCache.delete(cacheKey);
        return Result.ok(true);
    }

    @PreAuthorize("@ss.hasPerm('monitor:cache:list')")
    @GetMapping("/getValue/{cacheName}/{cacheKey}")
    public Result<Cache> getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey) {
        String cacheValue = redisCache.get(cacheKey);
        Cache cache = new Cache();
        cache.setCacheName(cacheName);
        cache.setCacheKey(cacheKey);
        cache.setCacheValue(cacheValue);
        return Result.ok(cache);
    }

    @PreAuthorize("@ss.hasPerm('monitor:cache:list')")
    @PostMapping("/clearCacheAll")
    public Result<Boolean> clearCacheAll() {
        Collection<String> cacheKeys = redisCache.keys("*");
        redisTemplate.delete(cacheKeys);
        return Result.ok(true);
    }
}
